// import { paste } from "@testing-library/user-event/dist/paste"
import { useCallback, useReducer, useState } from "react"



const UNDO = 'UNDO'
const REDO = 'REDO'
const SET = 'SET'
const RESET = 'RESET'

type State<T> = {
  past: T[],
  present: T,
  future: T[]
}
type Action<T> = { newPresent?: T, type: typeof UNDO | typeof REDO | typeof SET | typeof RESET }

const undoReducer = <T>(state: State<T>, action: Action<T>) => {
  const { past, present, future } = state
  const { newPresent } = action

  switch (action.type) {
    case UNDO: { 
      if (past.length === 0) return state;

      const previous = past[past.length - 1]
      const newPast = past.slice(0, past.length - 1)

      return {
        past: newPast,
        present: previous,
        future: [present, ...future]
      }
    };
    case REDO:{
      if (future.length === 0) return state

      const next = future[0]
      const newFuture = future.slice(1)

      return {
        past: [...past, present],
        present: next,
        future: newFuture
      }
    };
    case SET: {
      if (newPresent === present) return state

      return {
        past: [...past, present],
        present: newPresent,
        future: []
      }
    };
    case RESET:{
      return {
        past: [],
        present: newPresent,
        future: []
      }
    }
  }
  return state
}


export const useUndo = <T>(initialPresent: T) => {
  // const [past, setPast] = useState<T[]>([])
  // const [present, setPresent] = useState(initialPresent)
  // const [future,setFuture] = useState<T[]>([])

  // 将past，present，future整合在一起，不单独声明
  // const[state,setState] = useState<{
  //   past: T[],
  //   present: T,
  //   future: T[]
  //   // T[] 形式也可以写成 [] as T[]
  // }>({
  //   past:[],
  //   present: initialPresent,
  //   future:[]
  // })

  /**
   * useReducer 使用
   */
  const [state, dispatch] = useReducer(undoReducer, {
    past: [],
    present: initialPresent,
    future: []
  } as State<T>)



  // 整合后需将之前的 past,present,future 应为 state.past,...
  const canUndo = state.past.length !== 0
  const canRedo = state.future.length !== 0

  /**
   * 复杂形式，
   * undo,redo,rest,set使用useCallback（）需要传入canUndo,future,past,present 这些依赖
   */
  // const undo= useCallback(() =>{
  //   if(!canUndo) return

  //   const previous = past[past.length-1]
  //   const newPast = past.slice(0,past.length-1)

  //   setPast(newPast),
  //   setPresent(present),
  //   setFuture([present,...future])
  // },[canUndo,future,past,present])

  /**
   * 简洁形式，不用添加太多的依赖
   */
  // const undo = useCallback(() => {
  //   setState(currentState => {
  //     const { past, present, future } = currentState
  //     if (past.length === 0) return currentState;

  //     const previous = past[past.length - 1]
  //     const newPast = past.slice(0, past.length - 1)

  //     return {
  //       past: newPast,
  //       present: previous,
  //       future: [present, ...future]
  //     }
  //   })
  // }, [])

  // const redo = useCallback(() => {
  //   setState(currentState => {
  //     const { past, present, future } = currentState
  //     if (future.length === 0) return currentState

  //     const next = future[0]
  //     const newFuture = future.slice(1)

  //     return {
  //       past: [...past, present],
  //       present: next,
  //       future: newFuture
  //     }
  //   })
  // }, [])

  // const set = useCallback((newPresent: T) => {
  //   setState(currentState => {
  //     const { past, present, future } = currentState
  //     if (newPresent === present) return currentState

  //     return {
  //       past: [...past, present],
  //       present: newPresent,
  //       future: []
  //     }
  //   })
  // }, [])

  // const reset = useCallback((newPresent: T) => {
  //   setState(() => {
  //     return {
  //       past: [],
  //       present: newPresent,
  //       future: []
  //     }
  //   })
  // }, [])
 
  /**
   * @useReducer 
   */
  const undo = useCallback(()=>dispatch({type:UNDO}),[])

  const redo = useCallback(()=>dispatch({type:REDO}),[])
  
  const set = useCallback((newPresent:T)=>dispatch({type:SET,newPresent}),[])
  
  const reset = useCallback((newPresent:T)=>dispatch({type:RESET,newPresent}),[])
  return [
    state,
    { set, reset, undo, redo, canUndo, canRedo }
  ] as const
}